import { onMounted, ref, shallowRef } from 'vue'

export const backTopProps = {
  bottom: {
    default: 40,
    type: Number
  },
  right: {
    default: 40,
    type: Number
  },
  target: {
    default: '',
    type: String
  },
  visibilityHeight: {
    default: 200,
    type: Number
  }
} as const

export interface BackTopProps {
  bottom?: number
  isGroup?: boolean
  right?: number
  target?: string
  visibilityHeight?: number
}

export const useBackTop = (props: BackTopProps) => {
  // 定义滚动容器和目标元素
  const el = shallowRef<HTMLElement>()
  const container = shallowRef<Document | HTMLElement>()
  const visible = ref(false)

  /**
   * 处理滚动事件，控制 BackTop 按钮是否可见
   */
  const handleScroll = () => {
    if (el.value) {
      // 判断滚动位置是否超过指定高度，决定按钮的可见性
      visible.value = el.value.scrollTop >= (props?.visibilityHeight ?? 0)
    }
  }

  /**
   * 处理点击事件，将页面滚动到顶部
   */
  const handleClick = () => {
    el.value?.scrollTo({ behavior: 'smooth', top: 0 })
  }

  /**
   * 实现函数节流，防止滚动事件频繁触发
   * @param fn - 需要节流的函数
   * @param delay - 节流间隔时间（毫秒）
   */
  const throttle = (fn: () => void, delay: number) => {
    let lastCall = 0
    return () => {
      const now = Date.now()
      if (now - lastCall >= delay) {
        lastCall = now
        fn()
      }
    }
  }

  // 节流后的滚动事件处理函数
  const handleScrollThrottled = throttle(handleScroll, 300)

  /**
   * 监听滚动事件
   * @param target - 监听目标元素
   * @param event - 事件类型
   * @param handler - 事件处理函数
   */
  const addEventListener = (target: Document | HTMLElement | null, event: string, handler: () => void) => {
    if (target) {
      target.addEventListener(event, handler)
    }
  }

  // 组件挂载后执行
  onMounted(() => {
    // 默认使用 document 作为滚动容器
    container.value = document
    el.value = document.documentElement

    // 如果有指定 target，使用指定的元素作为滚动容器
    if (props.target) {
      el.value = document.querySelector<HTMLElement>(props.target) ?? undefined

      if (!el.value) {
        throw new Error(`target does not exist: ${props.target}`)
      }
      container.value = el.value
    }

    // 监听滚动事件，应用节流
    addEventListener(container.value, 'scroll', handleScrollThrottled)

    // 初始化时检查滚动位置
    handleScroll()
  })

  return {
    handleClick,
    visible
  }
}
